<template>
  <view>
    <text class="text" :style="[cusStyle, { color, fontSize }]">{{ data.formattedTime }}</text>
  </view>
</template>

<script lang="ts" setup>
  import { publicStyeProps } from '../mxp-tool/utils/public-props';
  import { isSameSecond, parseFormat, parseTimeData } from './utils';
  import { type PropType, onMounted, onUnmounted, shallowReactive, watch } from 'vue';
  import type { $AllColorStr, $SizeUnitStr } from '@/mxp-ui/mxp-tool/types/interface';
  defineOptions({
    name: 'mxp-count-down',
  });
  const props = defineProps({
    /** 倒计时时长，单位ms */
    time: { type: Number, default: 0 },
    /** 时间格式，DD-日，HH-时，mm-分，ss-秒，SSS-毫秒 */
    format: { type: String, default: 'HH:mm:ss' },
    /** 是否自动开始倒计时 */
    autoStart: { type: Boolean, default: true },
    /** 是否展示毫秒倒计时 */
    millisecond: { type: Boolean, default: false },
    /** 字体颜色 */
    color: { type: String as PropType<$AllColorStr>, default: '#606266' },
    /** 字体大小 */
    fontSize: { type: String as PropType<$SizeUnitStr>, default: '14px' },
    ...publicStyeProps,
  });
  defineSlots<{
    /** 主体内容 */
    default?: () => void;
  }>();
  const emits = defineEmits<{
    /** 倒计时改变 */
    (e: 'change', data: { days: number; hours: number; minutes: number; seconds: number; milliseconds: number }): void;
    /** 倒计时完成 */
    (e: 'finish'): void;
  }>();

  const data = shallowReactive({
    timer: null as NodeJS.Timeout | null,
    /** 格式化后的时间，如"03:23:21" */
    formattedTime: '0',
    /** 倒计时是否正在进行中 */
    runing: false,
    /** 结束的毫秒时间戳 */
    endTime: 0,
    /** 剩余的毫秒时间 */
    remainTime: 0,
  });

  watch(
    () => props.time,
    () => {
      reset();
    }
  );

  onMounted(() => {
    init();
  });

  onUnmounted(() => {
    clearTimeoutFun();
  });

  /** 初始化 */
  function init() {
    reset();
  }

  /** 开始倒计时 */
  function start() {
    if (data.runing) {
      return;
    }
    // 标识为进行中
    data.runing = true;
    // 结束时间戳 = 此刻时间戳 + 剩余的时间
    data.endTime = Date.now() + data.remainTime;
    toTick();
  }

  /** 根据是否展示毫秒，执行不同操作函数 */
  function toTick() {
    if (props.millisecond) {
      microTick();
    } else {
      macroTick();
    }
  }
  /** 宏 */
  function macroTick() {
    clearTimeoutFun();
    // 每隔一定时间，更新一遍定时器的值
    // 同时此定时器的作用也能带来毫秒级的更新
    data.timer = setTimeout(() => {
      // 获取剩余时间
      const remain = getRemainTime();
      // 重设剩余时间
      if (!isSameSecond(remain, data.remainTime) || remain === 0) {
        setRemainTime(remain);
      }
      // 如果剩余时间不为0，则继续检查更新倒计时
      if (data.remainTime !== 0) {
        macroTick();
      }
    }, 30);
  }

  /** 微任务 */
  function microTick() {
    clearTimeoutFun();
    data.timer = setTimeout(() => {
      setRemainTime(getRemainTime());
      if (data.remainTime !== 0) {
        microTick();
      }
    }, 50);
  }

  /** 获取剩余的时间 */
  function getRemainTime() {
    // 取最大值，防止出现小于0的剩余时间值
    return Math.max(data.endTime - Date.now(), 0);
  }

  /** 设置剩余的时间 */
  function setRemainTime(remain: number) {
    data.remainTime = remain;
    // 根据剩余的毫秒时间，得出该有天，小时，分钟等的值，返回一个对象
    const timeData = parseTimeData(remain);
    emits('change', timeData);
    // 得出格式化后的时间
    data.formattedTime = parseFormat(props.format, timeData);
    // 如果时间已到，停止倒计时
    if (remain <= 0) {
      pause();
      emits('finish');
    }
  }

  /** 重置倒计时 */
  function reset() {
    pause();
    data.remainTime = props.time;
    setRemainTime(data.remainTime);
    if (props.autoStart) {
      start();
    }
  }

  /** 暂停倒计时 */
  function pause() {
    data.runing = false;
    clearTimeoutFun();
  }

  /** 清空定时器 */
  function clearTimeoutFun() {
    data.timer && clearTimeout(data.timer);
    data.timer = null;
  }

  defineExpose({
    /** 开始倒计时 */
    start,
    /** 暂停倒计时 */
    pause() {
      console.log('aaa====');
      pause();
    },
    /** 重置倒计时 */
    reset,
  });
</script>
